package wordspaces.gui;

/*
 * GUI.java
 *
 * Created on 27. Mai 2007, 20:41
 */

//package wordspaces.gui;

import wordspaces.gui.threads.DistanceCalculatorWorker;
import java.io.IOException;
import wordspaces.gui.threads.BuildWordTableWorker;
import wordspaces.gui.listener.ModelPopupListener;
import wordspaces.gui.listener.ParserPopupListener;
import wordspaces.gui.listener.CompareWordsListener;
import wordspaces.gui.threads.IrregularVerbsStemmerWorker;
import Jama.Matrix;
import Jama.SingularValueDecomposition;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import plugins.ComputesDistance;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.PatternSyntaxException;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.RowFilter;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.text.BadLocationException;
import plugins.ScalarProductNorm;
import wordspaces.*;
import wordspaces.gui.listener.CheckBoxActionListener;
import wordspaces.gui.listener.DeleteActionListener;
import wordspaces.gui.listener.DublicateModelActionListener;
import wordspaces.gui.listener.MergeVectorsListener;
import wordspaces.gui.listener.FileParserActionListener;
import wordspaces.gui.listener.FilterExtremeValuesActionListener;
import wordspaces.gui.listener.RenameModelActionListener;
import wordspaces.gui.listener.SaveModelActionListener;
import wordspaces.gui.listener.SelectAllActionListener;
import wordspaces.gui.threads.BatchModelEvaluatorWorker;
import wordspaces.gui.threads.BatchProcessingWorker;
import wordspaces.gui.threads.FileFilterBalancerWorker;
import wordspaces.gui.threads.FileParserBalancerWorker;
import wordspaces.gui.threads.LoadModelThread;

/**
 *
 * @author  alexander
 */
public class GUI extends javax.swing.JFrame {

    /** Creates new form GUI */
    public GUI() {
        try {
            UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
        } catch (Exception ex) {
            System.out.println("Couldn't find com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel --> install Java 1.6.0_10t");
        } 

        checkBoxListener = new CheckBoxActionListener(this);

        initComponents();
        secondInit();

        gui.setTitle("WordSpaces Laboratorium");

        importPlugins();

        infoWindowFrame.setSize(580, 500);
        infoWindowFrame.setLocation(700, 10);
        infoWindowFrame.setVisible(true);

    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        infoWindowFrame = new javax.swing.JFrame();
        sizeLabel = new javax.swing.JLabel();
        mainTabbedPane = new javax.swing.JTabbedPane();
        contextPanel = new javax.swing.JPanel();
        contextScrollPane = new javax.swing.JScrollPane();
        contextTable = new javax.swing.JTable();
        wordScrollPane = new javax.swing.JScrollPane();
        wordTable = new javax.swing.JTable();
        historyScrollPane = new javax.swing.JScrollPane();
        historyTextArea = new javax.swing.JTextArea();
        searchTextField = new javax.swing.JTextField();
        wordVectorLabel = new javax.swing.JLabel();
        filterLabel = new javax.swing.JLabel();
        toolBar = new javax.swing.JToolBar();
        newModelButton = new javax.swing.JButton();
        loadModelButton = new javax.swing.JButton();
        saveModelButton = new javax.swing.JButton();
        loadTextSourceButton = new javax.swing.JButton();
        infoWindowButton = new javax.swing.JButton();
        distWindowButton = new javax.swing.JButton();
        sourcesTabbedPane = new javax.swing.JTabbedPane();
        sourcesScrollPane = new javax.swing.JScrollPane();
        textSourcesList = new javax.swing.JList();
        modelsTabbedPane = new javax.swing.JTabbedPane();
        modelsScrollPane = new javax.swing.JScrollPane();
        modelList = new javax.swing.JList();
        parserTabbedPane = new javax.swing.JTabbedPane();
        parserScrollPane = new javax.swing.JScrollPane();
        parserList = new javax.swing.JList();
        textSizeLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();
        stopBatchButton = new javax.swing.JButton();
        logPanel = new javax.swing.JPanel();
        logScrollPane = new javax.swing.JScrollPane();
        logTextArea = new javax.swing.JTextArea();
        mainMenuBar = new javax.swing.JMenuBar();
        modelMenu = new javax.swing.JMenu();
        deleteModelMenuItem = new javax.swing.JMenuItem();
        buildWordClassesMenuItem = new javax.swing.JMenuItem();
        parserMenu = new javax.swing.JMenu();
        fourParserMenuItem = new javax.swing.JMenuItem();
        customParserMenuItem = new javax.swing.JMenuItem();
        enableStopWordsMenuItem = new javax.swing.JCheckBoxMenuItem();
        enableFillerMenuItem = new javax.swing.JCheckBoxMenuItem();
        enableFocusWordsMenuItem = new javax.swing.JCheckBoxMenuItem();
        toolsMenu = new javax.swing.JMenu();
        fetchFromInternetMenuItem = new javax.swing.JMenuItem();
        distanceMenu = new javax.swing.JMenu();
        batchModelBuildingMenuItem = new javax.swing.JMenuItem();
        batchModelProcessingMenu = new javax.swing.JMenu();
        selectModelsMenuItem = new javax.swing.JMenuItem();
        selectGroupXMLMenuItem = new javax.swing.JMenuItem();
        batchModelProcessingMenuItem = new javax.swing.JMenuItem();
        helpMenu = new javax.swing.JMenu();
        aboutMenuItem = new javax.swing.JMenuItem();

        infoWindowFrame.setLocationByPlatform(true);

        sizeLabel.setText("0");

        contextTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        contextScrollPane.setViewportView(contextTable);

        wordTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        wordScrollPane.setViewportView(wordTable);

        org.jdesktop.layout.GroupLayout contextPanelLayout = new org.jdesktop.layout.GroupLayout(contextPanel);
        contextPanel.setLayout(contextPanelLayout);
        contextPanelLayout.setHorizontalGroup(
            contextPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(contextPanelLayout.createSequentialGroup()
                .add(wordScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(contextScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 250, Short.MAX_VALUE))
        );
        contextPanelLayout.setVerticalGroup(
            contextPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(wordScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 392, Short.MAX_VALUE)
            .add(contextScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 392, Short.MAX_VALUE)
        );

        mainTabbedPane.addTab("Context", contextPanel);

        historyTextArea.setColumns(20);
        historyTextArea.setRows(5);
        historyScrollPane.setViewportView(historyTextArea);

        mainTabbedPane.addTab("History", historyScrollPane);

        wordVectorLabel.setText("word vectors");

        filterLabel.setText("Search for:");

        org.jdesktop.layout.GroupLayout infoWindowFrameLayout = new org.jdesktop.layout.GroupLayout(infoWindowFrame.getContentPane());
        infoWindowFrame.getContentPane().setLayout(infoWindowFrameLayout);
        infoWindowFrameLayout.setHorizontalGroup(
            infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(infoWindowFrameLayout.createSequentialGroup()
                .addContainerGap()
                .add(infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(mainTabbedPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 539, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(infoWindowFrameLayout.createSequentialGroup()
                        .add(infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING, false)
                            .add(infoWindowFrameLayout.createSequentialGroup()
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(filterLabel))
                            .add(infoWindowFrameLayout.createSequentialGroup()
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED, 12, Short.MAX_VALUE)
                                .add(sizeLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 58, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)))
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                            .add(searchTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 117, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                            .add(wordVectorLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 98, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
                .addContainerGap(28, Short.MAX_VALUE))
        );
        infoWindowFrameLayout.setVerticalGroup(
            infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, infoWindowFrameLayout.createSequentialGroup()
                .add(mainTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 419, Short.MAX_VALUE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE, false)
                    .add(sizeLabel)
                    .add(wordVectorLabel))
                .add(7, 7, 7)
                .add(infoWindowFrameLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE, false)
                    .add(searchTextField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 22, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(filterLabel)))
        );

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        toolBar.setRollover(true);

        newModelButton.setText("New Model");
        newModelButton.setFocusable(false);
        newModelButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        newModelButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        newModelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newModelButtonActionPerformed(evt);
            }
        });
        toolBar.add(newModelButton);

        loadModelButton.setText("Load Model");
        loadModelButton.setFocusable(false);
        loadModelButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        loadModelButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        loadModelButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadModelActionPerformed(evt);
            }
        });
        toolBar.add(loadModelButton);

        saveModelButton.setText("Save Model");
        saveModelButton.setToolTipText("Save selected model to a file.");
        saveModelButton.setFocusable(false);
        saveModelButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        saveModelButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        saveModelButton.addActionListener(new SaveModelActionListener(this));
        toolBar.add(saveModelButton);

        loadTextSourceButton.setText("Load Text Source");
        loadTextSourceButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadTextSourceButtonActionPerformed(evt);
            }
        });
        toolBar.add(loadTextSourceButton);

        infoWindowButton.setText("Hide InfoWindow");
        infoWindowButton.setFocusable(false);
        infoWindowButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        infoWindowButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        infoWindowButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                infoWindowButtonActionPerformed(evt);
            }
        });
        toolBar.add(infoWindowButton);

        distWindowButton.setText("Show DistWindow");
        distWindowButton.setFocusable(false);
        distWindowButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
        distWindowButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
        distWindowButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                distWindowButtonActionPerformed(evt);
            }
        });
        toolBar.add(distWindowButton);

        textSourcesList.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        sourcesScrollPane.setViewportView(textSourcesList);

        sourcesTabbedPane.addTab("Text Sources", sourcesScrollPane);

        modelList.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        modelsScrollPane.setViewportView(modelList);

        modelsTabbedPane.addTab("Models", modelsScrollPane);

        parserList.setModel(new javax.swing.AbstractListModel() {
            String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };
            public int getSize() { return strings.length; }
            public Object getElementAt(int i) { return strings[i]; }
        });
        parserScrollPane.setViewportView(parserList);

        parserTabbedPane.addTab("Parser", parserScrollPane);

        textSizeLabel.setText("0 items");

        stopBatchButton.setText("Stop");
        stopBatchButton.setToolTipText("Stop batch processing after next finished model.");
        stopBatchButton.setEnabled(false);
        stopBatchButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopBatchButtonActionPerformed(evt);
            }
        });

        logTextArea.setColumns(20);
        logTextArea.setRows(5);
        logScrollPane.setViewportView(logTextArea);

        org.jdesktop.layout.GroupLayout logPanelLayout = new org.jdesktop.layout.GroupLayout(logPanel);
        logPanel.setLayout(logPanelLayout);
        logPanelLayout.setHorizontalGroup(
            logPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, logScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 745, Short.MAX_VALUE)
        );
        logPanelLayout.setVerticalGroup(
            logPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(logScrollPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 125, Short.MAX_VALUE)
        );

        modelMenu.setText("Model");

        deleteModelMenuItem.setText("Delete Model");
        modelMenu.add(deleteModelMenuItem);

        buildWordClassesMenuItem.setText("Build word classes");
        buildWordClassesMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buildWordClassesMenuItemActionPerformed(evt);
            }
        });
        modelMenu.add(buildWordClassesMenuItem);

        mainMenuBar.add(modelMenu);

        parserMenu.setText("Parser");

        fourParserMenuItem.setText("New Standard 4x4 Parser");
        fourParserMenuItem.setToolTipText("Creates a parser with stop word filtering and enabled filler");
        fourParserMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fourParserMenuItemActionPerformed(evt);
            }
        });
        parserMenu.add(fourParserMenuItem);

        customParserMenuItem.setText("New Custom Parser");
        customParserMenuItem.setActionCommand("custom parser");
        customParserMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                customParserMenuItemActionPerformed(evt);
            }
        });
        parserMenu.add(customParserMenuItem);

        enableStopWordsMenuItem.setSelected(false);
        enableStopWordsMenuItem.setText("Enable stop word filtering");
        enableStopWordsMenuItem.setToolTipText("Check to enable filtering of stop words");
        enableStopWordsMenuItem.setEnabled(false);
        enableStopWordsMenuItem.addActionListener(checkBoxListener);
        parserMenu.add(enableStopWordsMenuItem);

        enableFillerMenuItem.setSelected(false);
        enableFillerMenuItem.setText("Enable filler for stop words");
        enableFillerMenuItem.setToolTipText("Enables a filler for stop words to keep correct word distances");
        enableFillerMenuItem.setEnabled(false);
        enableFillerMenuItem.addActionListener(checkBoxListener);
        parserMenu.add(enableFillerMenuItem);

        enableFocusWordsMenuItem.setSelected(false);
        enableFocusWordsMenuItem.setText("Activate word selection list");
        enableFocusWordsMenuItem.setToolTipText("Select a text file with one focus word in each line");
        enableFocusWordsMenuItem.setEnabled(false);
        enableFocusWordsMenuItem.addActionListener(checkBoxListener);
        parserMenu.add(enableFocusWordsMenuItem);

        mainMenuBar.add(parserMenu);

        toolsMenu.setText("Tools");
        toolsMenu.setToolTipText("Build automatically one model for each parser that is in the parser list from the text sources that are in the source list.");

        fetchFromInternetMenuItem.setText("Fetch Text from Internet");
        fetchFromInternetMenuItem.setToolTipText("Enter a URL to fetch its text");
        fetchFromInternetMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fetchFromInternetMenuItemActionPerformed(evt);
            }
        });
        toolsMenu.add(fetchFromInternetMenuItem);

        distanceMenu.setText("Distances");
        toolsMenu.add(distanceMenu);

        batchModelBuildingMenuItem.setText("Batch model building");
        batchModelBuildingMenuItem.setToolTipText("Build automatically models for each parser in list by using the loaded text files.");
        batchModelBuildingMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                batchModelBuildingMenuItemActionPerformed(evt);
            }
        });
        toolsMenu.add(batchModelBuildingMenuItem);

        batchModelProcessingMenu.setText("Batch model processing");

        selectModelsMenuItem.setText("Select models to process");
        selectModelsMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectModelsMenuItemActionPerformed(evt);
            }
        });
        batchModelProcessingMenu.add(selectModelsMenuItem);

        selectGroupXMLMenuItem.setText("Select group xml file");
        selectGroupXMLMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                selectGroupXMLMenuItemActionPerformed(evt);
            }
        });
        batchModelProcessingMenu.add(selectGroupXMLMenuItem);

        batchModelProcessingMenuItem.setText("Start batch processing");
        batchModelProcessingMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                batchModelProcessingMenuItemActionPerformed(evt);
            }
        });
        batchModelProcessingMenu.add(batchModelProcessingMenuItem);

        toolsMenu.add(batchModelProcessingMenu);

        mainMenuBar.add(toolsMenu);

        helpMenu.setText("Help");

        aboutMenuItem.setText("About");
        aboutMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                aboutMenuItemActionPerformed(evt);
            }
        });
        helpMenu.add(aboutMenuItem);

        mainMenuBar.add(helpMenu);

        setJMenuBar(mainMenuBar);

        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, logPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, textSizeLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 143, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(org.jdesktop.layout.GroupLayout.LEADING, layout.createSequentialGroup()
                        .add(sourcesTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 406, Short.MAX_VALUE)
                        .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                        .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING)
                            .add(layout.createSequentialGroup()
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(modelsTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 224, Short.MAX_VALUE)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(parserTabbedPane, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 115, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                            .add(layout.createSequentialGroup()
                                .add(stopBatchButton)
                                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                                .add(progressBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 250, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))))
                    .add(org.jdesktop.layout.GroupLayout.LEADING, toolBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
            .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup()
                .add(toolBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 25, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(parserTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
                    .add(modelsTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE)
                    .add(sourcesTabbedPane, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 259, Short.MAX_VALUE))
                .add(6, 6, 6)
                .add(textSizeLabel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 30, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED)
                .add(logPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                .add(31, 31, 31)
                .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, progressBar, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 28, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)
                    .add(org.jdesktop.layout.GroupLayout.TRAILING, stopBatchButton))
                .addContainerGap())
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void distWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_distWindowButtonActionPerformed
        if(distWindowButton.getText().equals("Hide DistWindow")){
            distPanel.setVisible(false);
            distWindowButton.setText("Show DistWindow");
        }
        else {
            distPanel.setVisible(true);
            distWindowButton.setText("Hide DistWindow");
        }
}//GEN-LAST:event_distWindowButtonActionPerformed

    private void secondInit(){
        PrintStream ps = new PrintStream(new TextAreaOutputStream(logTextArea,((JScrollPane)logPanel.getComponent(0)).getVerticalScrollBar()));
        System.setOut(ps);
        
        /* this is the name cache that is entered in the parserCreateDialog */
        lastParserNameCache = "";
        //This is a treemap that saves all from model generated Table Models
        tableModelMap           = new HashMap<String, Object[][]>();
        gui                     = this;                 // this is not really nice !
        distPanel               = new DistancesPanel(gui);
        doubleComparator        = new DoubleComparator();
        sourcePopup             = new JPopupMenu();
        modelPopup              = new JPopupMenu();
        parserPopup             = new JPopupMenu();
        wordPopup               = new JPopupMenu();
        contextPopup            = new JPopupMenu();
        textSourcesListModel    = new DefaultListModel();
        parserListModel         = new DefaultListModel();
        modelListModel          = new DefaultListModel();

        
        /* Set the names for the popup menues to identify them by the SelectAllActionListener */
        sourcePopup.setName("sourcePopup");
        wordPopup.setName("wordPopup");
        contextPopup.setName("contextPopup");
        modelPopup.setName("modelPopup");
        parserPopup.setName("parserPopup");
        
        //when a model is changed by editing or deleting vectors or whatsoeverf then we create a notice about that
        //so we know we have to build a new dataArray[][] from the model in order to display the changes when we
        //click on the model's name in the list...
        modelHasChanged         = new HashMap<String, Boolean>();

        textSourcesList.setModel(textSourcesListModel);
        modelList.setModel(modelListModel);
        parserList.setModel(parserListModel);

        //build text sources popup menu
        JMenuItem filterText            = new JMenuItem("Apply filter");
        JMenuItem stemSourceMenuItem    = new JMenuItem("Apply irregular stemmer");
        JMenuItem parseMenuItem         = new JMenuItem("Parse to model");
        JMenuItem deleteInText          = new JMenuItem("Delete text");
        JMenuItem selectAllTexts        = new JMenuItem("Select all texts");
        sourcePopup.add(filterText);
        sourcePopup.add(stemSourceMenuItem);
        sourcePopup.add(parseMenuItem);
        sourcePopup.add(selectAllTexts);
        sourcePopup.add(deleteInText);

        //build model popup menu
        JMenuItem renameModelItem       = new JMenuItem("Rename");
        JMenuItem dublicateModelItem    = new JMenuItem("Dublicate");
        JMenuItem deleteInModels        = new JMenuItem("Delete model");
        modelPopup.add(renameModelItem);
        modelPopup.add(deleteInModels);
        modelPopup.add(dublicateModelItem);

        //build parser popup menu
        JMenuItem deleteInParser        = new JMenuItem("Delete parser");
        parserPopup.add(deleteInParser);

        //build the word vector popup menu
        JMenuItem getDistanceMenuItem   = new JMenuItem("Get distance");
        JMenuItem filterWords           = new JMenuItem("Filter frequencies");
        JMenuItem buildWordClassesItem  = new JMenuItem("Build word classes");
        JMenuItem svdWordMenuItem       = new JMenuItem("Apply SVD Dimension reduction");
        JMenuItem selectAllWords        = new JMenuItem("Select all words");
        JMenuItem deleteInWords         = new JMenuItem("Delete vector");
        JMenuItem compareVectors        = new JMenuItem("Compare");       
        //das Menue muss final sein, weil von innerer Klasse darauf zugegriffen wird
        final JMenu mergeVectors        = new JMenu("Merge Vectors");
        wordPopup.add(selectAllWords);
        wordPopup.add(getDistanceMenuItem);
        wordPopup.add(compareVectors);
        wordPopup.add(filterWords);
//        wordPopup.add(svdWordMenuItem);
        wordPopup.add(buildWordClassesItem);
        wordPopup.add(mergeVectors);
        wordPopup.add(deleteInWords);
        //tool tips
        getDistanceMenuItem.setToolTipText("Computes the distance between all selected vectors.");
        compareVectors.setToolTipText("Compares two vectors in order to discover reasons for similarity and diversity.");

        //build the context popup menu
        JMenu deleteMenu                = new JMenu("Delete");
        JMenuItem selectAllContextWords = new JMenuItem("Select all context words");
        JMenuItem deleteInContext       = new JMenuItem("Delete");
        JMenuItem deleteInAllContexts   = new JMenuItem("Delete in all contexts");
        JMenuItem filterContextWords    = new JMenuItem("Filter context frequencies");
        JMenuItem filterExtremeValues   = new JMenuItem("Filter a percentage of extreme values");
        contextPopup.add(filterExtremeValues);
        contextPopup.add(filterContextWords);
        contextPopup.add(deleteMenu);
        contextPopup.add(selectAllContextWords);
        deleteMenu.add(deleteInContext);
        deleteMenu.add(deleteInAllContexts);
        //tool tips
        filterContextWords.setToolTipText("Filters context frequencies from all selected vectors.");
        filterExtremeValues.setToolTipText("From all selected vectors remove 20% of the extreme values so that 60% remain.");
        deleteInAllContexts.setToolTipText("Deletes the selected words in every context in the current model.");

        textSourcesList.addMouseListener(new SourcePopupListener());
        modelList.addMouseListener(new ModelPopupListener(this,modelPopup));
        parserList.addMouseListener(new ParserPopupListener(this,parserPopup));
        wordTable.addMouseListener(new WordPopupListener());
        contextTable.addMouseListener(new ContextPopupListener());
        
        SelectAllActionListener selectAllListener = new SelectAllActionListener(this);     
        selectAllTexts.addActionListener(selectAllListener);
        selectAllWords.addActionListener(selectAllListener);
        selectAllContextWords.addActionListener(selectAllListener);
        
        DeleteActionListener deleteListener = new DeleteActionListener(this);
        deleteInContext.addActionListener(deleteListener);
        deleteInAllContexts.addActionListener(deleteListener);
        deleteInWords.addActionListener(deleteListener);
        deleteInModels.addActionListener(deleteListener);
        deleteInText.addActionListener(deleteListener);
        deleteInParser.addActionListener(deleteListener);
        
        parseMenuItem.addActionListener(new FileParserActionListener(this));
        dublicateModelItem.addActionListener(new DublicateModelActionListener(this));
        renameModelItem.addActionListener(new RenameModelActionListener(this));
        mergeVectors.addMenuListener(new MergeVectorsListener(this));
        filterExtremeValues.addActionListener(new FilterExtremeValuesActionListener(this));
        
        wordTableModel = new DefaultTableModel();
        wordTableModel = new javax.swing.table.DefaultTableModel(
            new String [] {
                "Words", "Frequency", "Context size"
            }, 0
        );
        wordTable.setModel(wordTableModel);

        contextTableModel = new javax.swing.table.DefaultTableModel(
            new String [] {
                "Words", "Frequency"
            }, 0
        );
        contextTable.setModel(contextTableModel);
        TableRowSorter<TableModel> contextSorter = new TableRowSorter<TableModel>(contextTableModel);
        contextSorter.setComparator(1, doubleComparator);
        contextTable.setRowSorter(contextSorter);

        searchTextField.getDocument().addDocumentListener(new DocumentListener() {
           public void insertUpdate(DocumentEvent e) { filterWordsinWordTable(); }
           public void removeUpdate(DocumentEvent e) { filterWordsinWordTable(); }
           public void changedUpdate(DocumentEvent e) {}
        });

        svdWordMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                int[] indices = wordTable.getSelectedRows();
                final SortedMap[] selectedVectors;
                String vectorName = null;
                if(indices.length > 0){
                    selectedVectors = new SortedMap[indices.length];
                    for(int i=0; i < indices.length; i++){
                        vectorName = (String) wordTableModel.getValueAt( wordTable.convertRowIndexToModel(indices[i]), 0);
                        selectedVectors[i] = model.getContextVector(vectorName);
                    }

                    progressBar.setMaximum(selectedVectors.length);
                    final BuildMatrix bmTask = new BuildMatrix(selectedVectors);
                    bmTask.addPropertyChangeListener(new PropertyChangeListener() {
                        public  void propertyChange(PropertyChangeEvent evt) {
                            if ("progress".equals(evt.getPropertyName())) {
                                progressBar.setValue(progressBar.getValue()+1);
                            }
                            if(bmTask.isDone()){
                                try {
//                                    consoleTextArea.append("Singular Value Decomposition++++++"+NEWLINE);
                                    Boolean transposed = false;
                                    progressBar.setValue(0);
                                    Matrix matrix = bmTask.get();
                                    if(selectedVectors.length < selectedVectors[0].size()){     //JAMA only calculates svd from MxN matrices
                                        matrix = matrix.transpose();                            //where m>=n . If this is not the case we need
                                        transposed = true;                                      //to transpose the matrix.
//                                        consoleTextArea.append("Matrix needed to be transposed"+NEWLINE);
                                    }
                                    SingularValueDecomposition svd = matrix.svd();
                                    Matrix u = svd.getU();
                                    Matrix s = svd.getS();
                                    Matrix v = svd.getV();
//                                    consoleTextArea.append("There are "+s.getColumnDimension()+"  Singular Values"+NEWLINE);
                                    for(int i=0; i<s.getColumnDimension(); i++)
 //                                           consoleTextArea.append(s.get(i, i)+ " ; ");

 //                                   consoleTextArea.append(NEWLINE);
                                    if(s.getColumnDimension() > 2){
 //                                       for(int i=2; i<s.getColumnDimension(); i++){
 //                                           consoleTextArea.append("Singular Value "+s.get(i, i)+ "  is set to 0"+NEWLINE);
 //                                           s.set(i, i, 0);
 //                                       }
                                    }
                                    Matrix result = u.times(s).times(v);

                                    if(transposed)
                                        result = result.transpose();

                                    SortedMap[] finalVectors = BuildMatrix.decomposeMatrixToMap(result, selectedVectors);

                                    for(int i=0; i<selectedVectors.length; i++){
                                        SortedMap vector = selectedVectors[i];
                                        Iterator iter = vector.keySet().iterator();
                                        Iterator finalIter = finalVectors[i].values().iterator();
                                        while(iter.hasNext()){
                                            vector.put(iter.next(), (Double)finalIter.next());
                                        }
                                    }
                                    showWordTable();
                                    textSizeLabel.setText("Singular Vector Decomposition done...");
                                } catch (InterruptedException ex) {
                                    Logger.getLogger("global").log(Level.SEVERE, null, ex);
                                } catch (ExecutionException ex) {
                                    Logger.getLogger("global").log(Level.SEVERE, null, ex);
                                }
                            }
                        }
                    });
                    bmTask.execute();
                }
            }
        });

        getDistanceMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                final int[] indices = wordTable.getSelectedRows();
                TreeMap<String, SortedMap> selection = null;
                if(indices.length >= 2){
                    contextTableModel.setRowCount(0);
                    selection = new TreeMap<String, SortedMap>();
                    for(int i=0; i < indices.length; i++){          //put the selected word vectors into selection
                        String word = (String) wordTableModel.getValueAt( wordTable.convertRowIndexToModel(indices[i]), 0);
                        selection.put(word, model.getContextVector(word));
                    }
                    textSizeLabel.setText("Calculating distances...");
                    progressBar.setMaximum(selection.size());
                    final DistanceCalculatorWorker task = new DistanceCalculatorWorker(selection, model.getCachedDistances(), distComputer);
                    task.addPropertyChangeListener(new PropertyChangeListener() {
                        int counter = 0;
                        public  void propertyChange(PropertyChangeEvent evt) {
                                if ("progress".equals(evt.getPropertyName())) {
                                    wordTableModel.setValueAt((model.getContextVector((String) evt.getNewValue())).size(),wordTable.convertRowIndexToModel(indices[counter]), 2);
                                    distPanel.wordDirTableModel.addRow(new Object[] {evt.getNewValue()});
                                    distPanel.wordsCountLabel.setText(Integer.parseInt(distPanel.wordsCountLabel.getText())+1+"");
                                    progressBar.setValue(counter++);

                                }
                                if(task.isDone()){
                                    textSizeLabel.setText("Distances calculated...");
                                    progressBar.setValue(0);
                                    modelHasChanged.put(model.toString(), true);
                                    distPanel.visualizeButton.setEnabled(true);
                                    distPanel.clearDistancesButton.setEnabled(true);
                                }
                            }
                    });

                    task.execute();
                    distPanel.setVisible(true);
                    distWindowButton.setText("Hide DistWindow");


                }else{
                    JOptionPane.showMessageDialog(null, "Please select at least 2 word vectors.", "Warning", JOptionPane.ERROR_MESSAGE);
                }
            }
        });

        compareVectors.addActionListener(new CompareWordsListener(this,wordTable));

        filterContextWords.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                String string = JOptionPane.showInputDialog("Filter words with a frequency in all context vectors that is smaller or equal to");
                if(string != null && !string.isEmpty()){
                    int inputValue = Integer.parseInt(string);
                    final int[] indices = wordTable.getSelectedRows();
                    for( int i=indices.length-1 ; i>=0 ; i-- ){
                        String vectorName = (String) wordTableModel.getValueAt( wordTable.convertRowIndexToModel(indices[i]), 0);
                        FrequencyFilter.filterFrequenciesInContext(model.getContextVector(vectorName),inputValue);
                        if(model.getContextVector(vectorName).size() == 0)
                            model.deleteWordVector(vectorName);
                    }

                    tableModelMap.remove(model.toString());
                    showWordTable();
                }
            }
        });

        filterText.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                final int[] indices = textSourcesList.getSelectedIndices();
                File[] files = new File[indices.length];
                for(int i=0; i < indices.length; i++)                 
                    files[i] = (File)textSourcesListModel.elementAt(indices[i]);                    
                
                textSourcesListModel.removeAllElements();
                textSizeLabel.setText("0 items");
                progressBar.setMaximum(indices.length);
                progressBar.setString("(0/"+indices.length+") finished");
                progressBar.setStringPainted(true);
                progressBar.setIndeterminate(true);
                final FileFilterBalancerWorker filter = new FileFilterBalancerWorker(files);
                filter.addPropertyChangeListener(new PropertyChangeListener() {
                    int counter = 0; boolean done = false;
                    public  void propertyChange(PropertyChangeEvent evt) {
                        if ("progress".equals(evt.getPropertyName())) {
                            textSourcesListModel.addElement(evt.getNewValue());
                            progressBar.setValue(counter++);
                            progressBar.setString("("+counter+"/"+indices.length+") finished");
                            textSizeLabel.setText(counter+" items");
                        }
                        else if(filter.isDone() && !done){
                            done = true;                          
                            progressBar.setValue(0);
                            progressBar.setString("");
                            progressBar.setStringPainted(false);
                            progressBar.setIndeterminate(false);
                            System.out.println("Finished filtering...");
                        }
                    }
                });

                filter.execute();
            }
        });

        filterWords.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                String string = JOptionPane.showInputDialog("Filter words with a frequency in text that is smaller or equal to");
                if(string != null && !string.isEmpty()){
                    int inputValue = Integer.parseInt(string);
                    FrequencyFilter.filterFrequenciesInWordMap(wordTableModel,model, inputValue);
                    modelHasChanged.put(model.toString(), true);
                }
            }
        });

        stemSourceMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                final int[] indices = textSourcesList.getSelectedIndices();
                File[] files = new File[indices.length];
                for(int i=0; i < indices.length; i++)                 
                    files[i] = (File)textSourcesListModel.elementAt(indices[i]);                    
                
                textSourcesListModel.removeAllElements();
                textSizeLabel.setText("0 items");
                progressBar.setMaximum(indices.length);
                progressBar.setStringPainted(true);
                progressBar.setIndeterminate(true);
                progressBar.setString("(0/"+indices.length+") finished");
                final IrregularVerbsStemmerWorker stemmer = new IrregularVerbsStemmerWorker(files);
                stemmer.addPropertyChangeListener(new PropertyChangeListener() {
                    int counter = 0;
                    public  void propertyChange(PropertyChangeEvent evt) {
                        if ("progress".equals(evt.getPropertyName())) {
                            textSourcesListModel.addElement(evt.getNewValue());
                            progressBar.setValue(counter++);
                            progressBar.setString("("+counter+"/"+indices.length+") finished");
                            textSizeLabel.setText(counter+" items");
                        }
                        else if(stemmer.isDone()){                           
                            progressBar.setValue(0);
                            progressBar.setString("");
                            progressBar.setStringPainted(false);
                            progressBar.setIndeterminate(false);
                            System.out.println("Finished stemming...");
                        }
                    }
                });

                stemmer.execute();
            }
        });

        buildWordClassesItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                buildWordClassesMenuItemActionPerformed(evt);
            }
        });   
    }

    private void customParserMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_customParserMenuItemActionPerformed
        new ParserCreateDialog(this);
    }//GEN-LAST:event_customParserMenuItemActionPerformed

    private void importPlugins(){
        File dir = new File("./WordSpaces/build/classes/plugins");
        String[] classnames = dir.list(new FilenameFilter(){
            public boolean accept(File verzeichnis, String name) {
                return name.endsWith(".class");
            }
        });

        for(String s:classnames){
            System.out.println("found "+s);
            if(!s.equals("ComputesDistance.class") && !s.equals("DimensionNotEqualException.class")){
                JCheckBoxMenuItem pluginItem = new JCheckBoxMenuItem(s.substring(0,s.indexOf(".")));
                distanceMenu.add(pluginItem);

                //set ScalarProductNorm as the standard
                if(pluginItem.getText().equals("ScalarProductNorm")){
                    distComputer = new ScalarProductNorm();
                    pluginItem.setSelected(true);
                }

                pluginItem.addActionListener(new ActionListener(){
                    public void actionPerformed(ActionEvent e) {
                        for(int i=0;i<distanceMenu.getItemCount(); i++){
                            distanceMenu.getItem(i).setSelected(false);
                        }
                        try {
                               Class clazz = Class.forName("plugins."+e.getActionCommand());
                               distComputer = (ComputesDistance)(clazz.getConstructor()).newInstance();
                               textSizeLabel.setText(e.getActionCommand()+" distance measure loaded...");
                               ((JMenuItem)e.getSource()).setSelected(true);
                           } catch (SecurityException ex) {
                                ex.printStackTrace();
                           } catch (NoSuchMethodException ex) {
                                ex.printStackTrace();
                           } catch (IllegalArgumentException ex) {
                                ex.printStackTrace();
                           } catch (InstantiationException ex) {
                                ex.printStackTrace();
                           } catch (InvocationTargetException ex) {
                                ex.printStackTrace();
                           } catch (IllegalAccessException ex) {
                                ex.printStackTrace();
                           } catch (ClassNotFoundException ex) {
                                ex.printStackTrace();
                           }
                     }
                });
            }
        }
    }

    private void fetchFromInternetMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fetchFromInternetMenuItemActionPerformed
        new EnterURLDialog(this);
    }//GEN-LAST:event_fetchFromInternetMenuItemActionPerformed

    private void buildWordClassesMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_buildWordClassesMenuItemActionPerformed
        progressBar.setMaximum(model.getDirectorySize());
        final WordClassBuilder task = new WordClassBuilder(model);
        task.addPropertyChangeListener(new PropertyChangeListener() {
            public  void propertyChange(PropertyChangeEvent evt) {
                if ("progress".equals(evt.getPropertyName())) {
                    progressBar.setValue(progressBar.getValue()+1);
                }else if("merge".equals(evt.getPropertyName())){
                    System.out.println(evt.getNewValue());
                }else if("remove".equals(evt.getPropertyName())){
                    wordTableModel.removeRow((Integer) evt.getNewValue());
                }
                if(task.isDone()){
                    textSizeLabel.setText("Building word classes is done...");
                    progressBar.setValue(0);
                    sizeLabel.setText(model.getDirectorySize()+"");
                }
            }
        });
        task.execute();
        modelHasChanged.put(model.toString(), true);
    }//GEN-LAST:event_buildWordClassesMenuItemActionPerformed

    private void fourParserMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fourParserMenuItemActionPerformed
        parser = new Parser(4,4);
        parser.enableFiller(true);
        parser.enableStopWordsFilter(checkBoxListener.createSetFromFile("Select stop words file"));
        addParser(parser);
        System.out.println("New Parser with Filler="+parser.isFillerEnabled()+" and Stop Words="+parser.isStopWordsEnabled()+" created...");
}//GEN-LAST:event_fourParserMenuItemActionPerformed

    private void filterWordsinWordTable(){
        String text = null;
        try {
            text = searchTextField.getDocument().getText(0, searchTextField.getDocument().getLength());
        } catch (BadLocationException ex) {
            ex.printStackTrace();
        }
        if (text.length() == 0) {
            wordTableSorter.setRowFilter(null);
        } else {
            try {
               wordTableSorter.setRowFilter(RowFilter.regexFilter(text));
            } catch (PatternSyntaxException pse) {
               System.err.println("Bad regex pattern");
            }
        }
    }

    public synchronized void showWordTable(){
        wordTableModel.setRowCount(0);
        contextTableModel.setRowCount(0);
        /* If tableModel has not been constructed before, we construct it and save it in tableModelMap*/
        if(!tableModelMap.containsKey(model.toString()) || (modelHasChanged.containsKey(model.toString()) && modelHasChanged.get(model.toString()))){
            System.out.println("Table Model is being build...");
            progressBar.setMaximum(model.getDirectorySize());
            final BuildWordTableWorker task = new BuildWordTableWorker(model);
            task.addPropertyChangeListener(new PropertyChangeListener() {
                boolean done = false;  //workaround,ensures that task.isDone is only once done...
                /*This is to avoid duplicate events */
                String vectorName = "";
                public void propertyChange(PropertyChangeEvent evt) {    
                    if ("progress".equals(evt.getPropertyName())) {
                        Object[] data = (Object[])evt.getNewValue();
           //             if(!vectorName.equals(data[0])){            //not very nice !!!
           //                 wordTableModel.addRow(data);
                            sizeLabel.setText(progressBar.getValue()+1+"");
                            progressBar.setValue(progressBar.getValue()+1);
           //                 vectorName = (String) data[0];
           //             }
                    }
                    else if(task.isDone() && !done){
                        done = true;
                        try {
                            Object[][] dataArray = task.get();
                            tableModelMap.put(model.toString(), dataArray);
                            wordTableModel.setDataVector(dataArray,new Object[]{"Words", "Frequency", "Context size"});
                            /* Sorter must be initialized again */
                            IntegerComparator intComparator = new IntegerComparator();
                            wordTableSorter = new TableRowSorter<TableModel>(wordTableModel);
                            wordTableSorter.setComparator(1, intComparator);
                            wordTableSorter.setComparator(2, intComparator);
                            wordTable.setRowSorter(wordTableSorter);
                            modelHasChanged.put(model.toString(), false);
                            sizeLabel.setText(model.getDirectorySize()+"");
                            System.out.println("Table Model created for "+model+"...");
                            progressBar.setValue(0);                       
                        } catch (InterruptedException ex) {
                            Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                        } catch (ExecutionException ex) {
                            Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
                        }
                    }
                }
            });
            task.execute();
        }else{      //tableModel was constructed before or wasn't modified
            Object[][] dataArray = tableModelMap.get(model.toString());
            wordTableModel.setDataVector(dataArray,new Object[]{"Words", "Frequency", "Context size"});
            sizeLabel.setText(model.getDirectorySize()+"");
        }
    }

    public void showHistoryTable(){
        if(model != null){
            historyTextArea.setText("");
            historyTextArea.append("Number of parsed documents in this model is " + model.getParsedSources().size() + "\n" + "++++++++++++" + "\n");
            for (String s : model.getParsedSources()) {
                historyTextArea.append(s + "\n");
            }
        }
    }
    
    private void newModelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newModelButtonActionPerformed
    	String name = JOptionPane.showInputDialog("Please type in the models name");
        if(name != null && !name.isEmpty()){
            Model m = new Model(name);
            addModel(m);
            System.out.println("New model '"+m+"' created...");

            //automatically selects the new model if no model was selected before
            if(model == null){
    		setModel(m);
                modelList.setSelectedIndex(modelListModel.getSize()-1);     //select the last added model
                infoWindowFrame.setTitle(model.toString());
            }
        }
    }//GEN-LAST:event_newModelButtonActionPerformed

    private void infoWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_infoWindowButtonActionPerformed
    	if(infoWindowFrame.isVisible()){
    		infoWindowFrame.setVisible(false);
    		infoWindowButton.setText("Show InfoWindow");
    	}
    	else {
    		infoWindowFrame.setVisible(true);
    		infoWindowButton.setText("Hide InfoWindow");
    	}
}//GEN-LAST:event_infoWindowButtonActionPerformed

    private void loadTextSourceButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadTextSourceButtonActionPerformed
        File[] files = LoadFiles("Select text files",".txt",true);
        if(files != null){
            for(int i=0; i< files.length; i++){
                if(files[i].isFile())
                    textSourcesListModel.addElement(files[i]);
                else{
                    for(String fileName: files[i].list()){
                        if(fileName.charAt(0) != '.')
                            textSourcesListModel.addElement(new File(files[i]+"/"+fileName));
                    }
                }
            }
        }
        textSizeLabel.setText(textSourcesListModel.getSize()+" items");       
    }//GEN-LAST:event_loadTextSourceButtonActionPerformed

    private void aboutMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-    	 FIRST:event_aboutMenuItemActionPerformed
        JOptionPane.showMessageDialog(null, "Programed by Alexander Frey. Email to afrey@uos.de", "About...", 			JOptionPane.INFORMATION_MESSAGE);

    }                                             

    private void loadModelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadModelActionPerformed
        File[] files = LoadFiles("Select the model",".model",false);
        if(files != null){
            progressBar.setMaximum(1);
            progressBar.setString("Loading...");
            progressBar.setStringPainted(true);
            progressBar.setIndeterminate(true);
            final LoadModelThread thread = new LoadModelThread(files[0]);
            thread.addPropertyChangeListener(new PropertyChangeListener() {
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("modelLoaded".equals(evt.getPropertyName())) {
                        Model m = (Model)evt.getNewValue();
                        addModel(m);
                        //automatically selects the new model if no model was selected before
                        if(getModel() == null){
                            setModel(m);
                            getModelList().setSelectedIndex(((DefaultListModel)gui.getModelList().getModel()).getSize()-1);     //select the last added model
                            showWordTable();
                            showHistoryTable();
                        }
                        System.out.println("Model '"+model+"' with "+model.getDirectorySize()+" words loaded...");
                    }
                    if(thread.isDone()){
                        progressBar.setIndeterminate(false);
                        progressBar.setString("");
                        progressBar.setValue(0);
                        progressBar.setStringPainted(false);
                    }
                }                
            });  
            thread.execute();
        }
    }//GEN-LAST:event_loadModelActionPerformed

    private void batchModelBuildingMenuItemActionPerformed(java.awt.event.ActionEvent evt) {                                                        
    	Vector<File> files = new Vector();
    	final Parser[] parserVector = new Parser[parserListModel.getSize()];
    	/* Check if text sources and parser are avaiable... */
    	if(textSourcesListModel.getSize() >= 1 && parserListModel.getSize() >= 1 ){            
            /* Put all files from sources list into vector */
            for(int i=0;i<textSourcesListModel.getSize();i++)
                files.addElement((File) textSourcesListModel.elementAt(i));          
                                                         
            /* Put all parser from parser list into the parser vector */
            for(int i=0;i<parserListModel.getSize();i++)
                parserVector[i] = (Parser) parserListModel.elementAt(i);
        
            progressBar.setIndeterminate(false);
            progressBar.setMaximum(parserVector.length*files.size());
            progressBar.setString("(0/"+parserVector.length+") models builded");
            progressBar.setStringPainted(true);
            batchWorker = new BatchProcessingWorker(files,parserVector);
            batchWorker.addPropertyChangeListener(new PropertyChangeListener() {
                boolean done = false;
                int fileProg = 0;           //for the file progress
                int modelProg = 0;          //for the model progress
                public  void propertyChange(PropertyChangeEvent evt) {
                    /* one file has been parsed */
                    if ("progress".equals(evt.getPropertyName())) {
                        System.out.println("Finished parsing of "+((File)evt.getNewValue()).getName()+"...");
                        progressBar.setValue(++fileProg);
                    }
                    /* building of one model is finished */
                    if ("finished".equals(evt.getPropertyName())) {               
                        progressBar.setString("("+(++modelProg)+"/"+parserVector.length+") models finished");
                        System.out.println("Model saved to "+evt.getNewValue());
                    }

                    if("cancelled".equals(evt.getPropertyName())){
                        System.out.println("Batch model building cancelled !");
                    }
                    /* first check !done because batchWorker is set to null in body ! */
                    if(!done && batchWorker.isDone()){
                        done = true;
                        System.out.println("Finished batch model building...");
                        progressBar.setString("");
                        progressBar.setStringPainted(false);
                        progressBar.setValue(0);
                        progressBar.setIndeterminate(false);
                        batchWorker = null;
                        stopBatchButton.setEnabled(false);
                    }
                }
            });
            batchWorker.execute();
            stopBatchButton.setEnabled(true);
        }
        else{
            JOptionPane.showMessageDialog(null, "There must be at least one parser and text source.", "Warning", JOptionPane.ERROR_MESSAGE);
        }
    }

    private void stopBatchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stopBatchButtonActionPerformed
        if(batchWorker != null || fileParserBalancerWorker != null){
            if(batchWorker != null){
                batchWorker.cancel(false);
            }
            else if(fileParserBalancerWorker != null){
                fileParserBalancerWorker.cancel(false);
            }
            
            progressBar.setString("");
            progressBar.setStringPainted(false);
            progressBar.setValue(0);         
        }
        
        stopBatchButton.setEnabled(false);
    }//GEN-LAST:event_stopBatchButtonActionPerformed

    private void selectModelsMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectModelsMenuItemActionPerformed
        selectedModels = LoadFiles("Select model files",".model",true);
    }//GEN-LAST:event_selectModelsMenuItemActionPerformed

    private void selectGroupXMLMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectGroupXMLMenuItemActionPerformed
        groupXMLFile = LoadFiles("Select group xml file",".xml",false);
    }//GEN-LAST:event_selectGroupXMLMenuItemActionPerformed

    private void batchModelProcessingMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_batchModelProcessingMenuItemActionPerformed
        while(groupXMLFile == null || selectedModels == null){
            selectedModels = LoadFiles("Select model files",".model",true);
            groupXMLFile = LoadFiles("Select group xml file",".xml",false);
        }
        final FileWriter writer;
        try {
            writer = new FileWriter(new File("results.txt"), true);
            progressBar.setIndeterminate(true);
            progressBar.setMaximum(selectedModels.length);
            progressBar.setString("(0/"+selectedModels.length+") models finished");
            progressBar.setStringPainted(true);
            final BatchModelEvaluatorWorker thread = new BatchModelEvaluatorWorker(selectedModels,groupXMLFile[0],distComputer);
            thread.addPropertyChangeListener(new PropertyChangeListener() {
                int progress = 0;

                public  void propertyChange(PropertyChangeEvent evt) {
                    /* one file has been parsed */
                    if ("results".equals(evt.getPropertyName())) {
                        double[] results = (double[]) evt.getNewValue();
                        Model m = (Model) evt.getOldValue();
                        progressBar.setValue(++progress);
                        progressBar.setString("("+progress+"/"+selectedModels.length+") models finished");

                        /* now we try to write the result into a file */
                        try {
                            writer.write(m + ":: Grade " + (1-(results[0] / results[2]))+" ( 1 - "+(results[0])+" / "+results[2]+") Errors:"+results[1]+"\n");
                            writer.flush();
                        } catch (IOException ex) {
                            System.out.println(ex.getMessage());
                        }
                    
                        System.out.println(m+":: Grade "+(1-(results[0] / results[2]))+" ( 1 - "+(results[0])+" / "+results[2]+") Errors:"+results[1]);
                    }
                    /* first check !done because batchWorker is set to null in body ! */
                    if(thread.isDone()){
                        try {
                            writer.close();
                        } catch (IOException ex) {
                            System.out.println(ex.getMessage());
                        }
                        groupXMLFile = null;
                        selectedModels = null;
                        batchWorker = null;
                        progressBar.setString("");
                        progressBar.setStringPainted(false);
                        progressBar.setValue(0);  
                        progressBar.setIndeterminate(false);
                        stopBatchButton.setEnabled(false);
                        System.out.println("Finished batch processing...");
                    }
                }
            });
            thread.execute();
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }           
    }//GEN-LAST:event_batchModelProcessingMenuItemActionPerformed
    

    public void addFileParserBalancerWorker(FileParserBalancerWorker w){
        fileParserBalancerWorker = w;
        stopBatchButton.setEnabled(true);
    }
    
    public void removeFileParserBalancerWorker(FileParserBalancerWorker w){
        fileParserBalancerWorker = null;
        stopBatchButton.setEnabled(false);
    }

    public Model getModel(){
        return model;
    }
    
    public Parser getParser(){
        return parser;
    }
    
    public DistancesPanel getDistancesPanel(){
        return distPanel;
    }

    public JTable getWordTable(){
        return wordTable;      
    }
    
    public JTable getContextTable(){
        return contextTable;
    }
    
    public JList getTextSourcesList(){
        return textSourcesList;
    }
    
    public JList getModelList(){
        return modelList;
    }
    
    public JList getParserList(){
        return parserList;
    }
    
    public JLabel getSizeLabel(){
        return sizeLabel;
    }
    
    public JLabel getTextSizeLabel(){
        return textSizeLabel;
    }
    
    public JFrame getInfoWindow(){
        return infoWindowFrame;
    }
    
    public Map getTableModelMap(){
        return tableModelMap;
    }
    
    public JMenuBar getMainMenu(){
        return mainMenuBar;
    }
    
    public JTextArea getHistoryTextArea(){
        return historyTextArea;
    }
    
    public JProgressBar getProgressBar(){
        return progressBar;
    }
    
    public void enableFocusWords(boolean on){
        enableFocusWordsMenuItem.setEnabled(on);
    }
    
    public void selectFocusWords(boolean on){
        enableFocusWordsMenuItem.setSelected(on);
    }
       
    public void enableParserParameter(boolean on){
        enableFillerMenuItem.setEnabled(on);
        enableStopWordsMenuItem.setEnabled(on);
    }
    
    public void selectParserParameter(boolean on){
        enableFillerMenuItem.setSelected(on);
        enableStopWordsMenuItem.setSelected(on);
    }
    
    public void setParser(Parser p){
        if(p == null){
            parser = null;
            parserList.clearSelection();
            selectFocusWords(false);
            enableFocusWords(false);
            enableParserParameter(false);
            selectParserParameter(false);
        }
        else{
            parser = p;
            enableFocusWordsMenuItem.setEnabled(true);         //this must be in both cases enabled  
            enableFillerMenuItem.setEnabled(true);
            enableStopWordsMenuItem.setEnabled(true);
            enableFocusWordsMenuItem.setSelected(parser.isFocusWordsEnabled());
            enableFillerMenuItem.setSelected(parser.isFillerEnabled());
            enableStopWordsMenuItem.setSelected(parser.isStopWordsEnabled());             
        }
    }
    
    public void addParser(Parser p){
        if(p != null){
            parserListModel.addElement(p);
            parserList.setSelectedIndex(parserListModel.getSize()-1);
            setParser(p);
        }
    }
    
    public void setModel(Model m){
        model = m;
        if(model != null)
            setTitle("WordSpaces Laboratorium ( "+model+" )");
        else
            setTitle("WordSpaces Laboratorium");
    }
    
    public void addModel(Model m){
        modelListModel.addElement(m);
    }
    
    public void setModelhasChanged(Model m){
        modelHasChanged.put(m.toString(), true);
    }
    
    public HashMap getModelChangedMap(){
        return modelHasChanged;
    }

    private File[] LoadFiles(String title, final String fileType, boolean multiSelection){
        JFileChooser chooser = new JFileChooser();
        chooser.setDialogTitle(title);
        chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES);
        chooser.setMultiSelectionEnabled(multiSelection);
        chooser.setFileFilter(new javax.swing.filechooser.FileFilter() {
            public boolean accept(File f) {
                if(f.getName().toLowerCase().endsWith(fileType) || f.isDirectory()){
                    return true;
                }
                else 
                    return false;
            }
            public String getDescription() {
                return fileType+" files";
            }
        });

        if(multiSelection && chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
            return chooser.getSelectedFiles();
        else if(!multiSelection && chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION){
            File[] array = new File[1];
            array[0] = chooser.getSelectedFile();
            return array;
        }
           
            
        return null;
    }


    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        if(args.length > 0){
            new ConsoleModus(args);
        }
        else{
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new GUI().setVisible(true);              
                }
            });
        }
    }

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JMenuItem aboutMenuItem;
    private javax.swing.JMenuItem batchModelBuildingMenuItem;
    private javax.swing.JMenu batchModelProcessingMenu;
    private javax.swing.JMenuItem batchModelProcessingMenuItem;
    private javax.swing.JMenuItem buildWordClassesMenuItem;
    private javax.swing.JPanel contextPanel;
    private javax.swing.JScrollPane contextScrollPane;
    private javax.swing.JTable contextTable;
    private javax.swing.JMenuItem customParserMenuItem;
    private javax.swing.JMenuItem deleteModelMenuItem;
    public javax.swing.JButton distWindowButton;
    private javax.swing.JMenu distanceMenu;
    public javax.swing.JCheckBoxMenuItem enableFillerMenuItem;
    public javax.swing.JCheckBoxMenuItem enableFocusWordsMenuItem;
    public javax.swing.JCheckBoxMenuItem enableStopWordsMenuItem;
    private javax.swing.JMenuItem fetchFromInternetMenuItem;
    private javax.swing.JLabel filterLabel;
    private javax.swing.JMenuItem fourParserMenuItem;
    private javax.swing.JMenu helpMenu;
    private javax.swing.JScrollPane historyScrollPane;
    private javax.swing.JTextArea historyTextArea;
    private javax.swing.JButton infoWindowButton;
    private javax.swing.JFrame infoWindowFrame;
    private javax.swing.JButton loadModelButton;
    private javax.swing.JButton loadTextSourceButton;
    private javax.swing.JPanel logPanel;
    private javax.swing.JScrollPane logScrollPane;
    private javax.swing.JTextArea logTextArea;
    private javax.swing.JMenuBar mainMenuBar;
    private javax.swing.JTabbedPane mainTabbedPane;
    private javax.swing.JList modelList;
    private javax.swing.JMenu modelMenu;
    private javax.swing.JScrollPane modelsScrollPane;
    private javax.swing.JTabbedPane modelsTabbedPane;
    private javax.swing.JButton newModelButton;
    private javax.swing.JList parserList;
    private javax.swing.JMenu parserMenu;
    private javax.swing.JScrollPane parserScrollPane;
    private javax.swing.JTabbedPane parserTabbedPane;
    protected javax.swing.JProgressBar progressBar;
    private javax.swing.JButton saveModelButton;
    private javax.swing.JTextField searchTextField;
    private javax.swing.JMenuItem selectGroupXMLMenuItem;
    private javax.swing.JMenuItem selectModelsMenuItem;
    private javax.swing.JLabel sizeLabel;
    private javax.swing.JScrollPane sourcesScrollPane;
    private javax.swing.JTabbedPane sourcesTabbedPane;
    private javax.swing.JButton stopBatchButton;
    protected javax.swing.JLabel textSizeLabel;
    private javax.swing.JList textSourcesList;
    private javax.swing.JToolBar toolBar;
    private javax.swing.JMenu toolsMenu;
    private javax.swing.JScrollPane wordScrollPane;
    private javax.swing.JTable wordTable;
    private javax.swing.JLabel wordVectorLabel;
    // End of variables declaration//GEN-END:variables
    protected javax.swing.table.DefaultTableModel contextTableModel;
    protected javax.swing.table.DefaultTableModel wordTableModel;
    protected DefaultListModel textSourcesListModel;
    protected DefaultListModel modelListModel;
    protected DefaultListModel parserListModel;
    private JPopupMenu sourcePopup;
    private JPopupMenu modelPopup;
    private JPopupMenu parserPopup;
    private JPopupMenu wordPopup;
    private JPopupMenu contextPopup;
    private Parser parser;
    private Model model;
    private GUI gui;
    private ComputesDistance distComputer;
    private TableRowSorter<TableModel> wordTableSorter;
    private DoubleComparator doubleComparator;
    protected DistancesPanel distPanel;
    protected Map<String, Object[][]> tableModelMap;
    private HashMap<String, Boolean> modelHasChanged;
    private CheckBoxActionListener checkBoxListener;
    public String lastParserNameCache;
    private BatchProcessingWorker batchWorker;
    /* To be able to interrupt the parsing process,we keep an reference to the thread
     * which can be interrupted... */
    private FileParserBalancerWorker fileParserBalancerWorker;

    /* These should get initialized when batch processing models... */
    private File[] selectedModels;
    private File[] groupXMLFile;    //only index 0 gets initialized
   


    class ContextPopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger() && e.getButton() == e.BUTTON3) {
                contextPopup.show(e.getComponent(),
                e.getX(), e.getY());
            }
        }
    }

    class WordPopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger() && e.getButton() == e.BUTTON3) {
                wordPopup.show(e.getComponent(),
                e.getX(), e.getY());
            }
            else if(e.getButton() == e.BUTTON1){                     
                if(wordTable.getSelectedRow() != -1){                     
                    contextTableModel.setRowCount(0);
                    String selectedWord = (String) wordTableModel.getValueAt(
                            wordTable.convertRowIndexToModel(wordTable.getSelectedRow()),0);
  //                  System.out.println("Start building context table!");
                    Iterator<String> iter = model.getContextVector(selectedWord).keySet().iterator();
                    String contextWord;
                    while(iter.hasNext()){
                        contextWord = iter.next();
                        contextTableModel.addRow(new Object[] {
                            contextWord, model.getContextVector(selectedWord).get(contextWord)
                        });
                    }
                    System.out.println("Finished context table building!");
                }
            }
        }
    }

    class SourcePopupListener extends MouseAdapter {
        public void mousePressed(MouseEvent e) {
            if (e.isPopupTrigger() && e.getButton() == e.BUTTON3) {
                sourcePopup.show(e.getComponent(),
                e.getX(), e.getY());
            }
        }
    }
    
    class TextAreaOutputStream extends OutputStream {
        JTextArea textArea;
        JScrollBar scrollBar;
        DateFormat dateFormater;
        StringBuffer buffer;
        
        public TextAreaOutputStream(JTextArea a, JScrollBar b){
            textArea = a;
            scrollBar = b;
            dateFormater = DateFormat.getTimeInstance(DateFormat.MEDIUM);
            buffer = new StringBuffer();
        }
        
        @Override
        public void write(int c) throws IOException {
            if(c == 10){
                textArea.append(dateFormater.format(new Date())+"  "+buffer.toString()+"\n");
                buffer.delete(0, buffer.length());
            }
            else 
                buffer.append((char)c);
            
            scrollBar.setValue(scrollBar.getMaximum());
        }
        
    }
    
    
}

